package Grantsfire::Controller::Grant;

use strict;
use warnings;
use DateTime;
use Time::Local qw(timelocal_nocheck timelocal);
use XML::Simple;
use Grantsfire::Geocoder;
use base 'Catalyst::Base';

sub detail : Regex('^grant$') {
    my ($self, $c, $id) = @_;
    $c->forward('/grant/search', [rows=>1, page=>$c->req->params->{detail}]); # load up search results
    $c->stash->{template} = 'grant.tt';
    $c->stash->{grant_id} = $id;
    $c->stash->{grants} = [$c->model("GF::Entry")->find($id)] unless $c->stash->{grants} and @{$c->stash->{grants}};
}

sub search_xml : Local {
	my ($self, $c) = @_;
	
	my $search_res = $c->forward('search_raw') || {};
	$c->res->body(XML::Simple::XMLout($search_res) || '');
}

sub search_feed : Local {
	my ($self, $c) = @_;
	
	$c->stash->{feed_grants} = $c->forward('search_raw_entries');
	$c->stash->{feed_dest_uri} = $c->uri_for('/grant/search', $c->req->params);
	my $feed = $c->forward('/feed/generate');
	
    $c->res->content_type('application/atom+xml');
    $c->res->body($feed->as_xml);
}

sub search_raw_entries : Private {
	my ($self, $c) = @_;
	
	$c->res->content_type('application/xml');
	
	my $query = $c->forward('get_query');
	
	my ($start_date_param, $end_date_param) = ($c->req->param('startDate'), $c->req->param('endDate'));

	if ($start_date_param) {
		my $start_date = DateTime->from_epoch(epoch => $start_date_param);
		push @{$query->{'-and'}}, { dtstart => { '>=' => $start_date } };
	}

	if ($end_date_param) {
		my $end_date = DateTime->from_epoch(epoch => $end_date_param);
		push @{$query->{'-and'}}, { dtstart => { '<=' => $end_date } };
	}
	
	my $rs = $c->model('GF::Entry')->search($query, {
		order_by => 'dtstart',
        join => [qw/grantor grantee/],
	});
	
	return [$rs->all]
}

sub search_raw : Private {
	my ($self, $c) = @_;
	
	my $entries_ref = $c->forward('search_raw_entries') || [];

	my (@grants, @grant_vcards);
	my %tags;
	my $dollar_total;
	my $count_total;
    my $do_geocode_lookup = $c->req->param('geocode') && Grantsfire::Geocoder->googlemaps_api_key($c);

    # geocode grant vcards
    @grant_vcards = grep { $_ } map { $_->grant_vcard } @$entries_ref;

    my $geo_info = Grantsfire::Geocoder->geocode_vcards($c, @grant_vcards); # $vcardid => $geoinfo

	foreach my $entry (@$entries_ref) {		
		# create hashref to store information about this entry
		my $entry_ret = {};

		# copy db cols into entry_ret
		my %entry_cols = $entry->get_columns;
		while (my ($k, $v) = each %entry_cols) {
			$entry_ret->{$k} = $v;
		}
		
		# add extra info to entry_ret (unix timestamp of date and tags)
		$entry_ret->{date} = $entry->dtstart->epoch;
		my $entry_tags = [];
		$entry_ret->{tag} = $entry_tags;
		push @$entry_tags, $_->tag foreach $entry->tags;
		
		# add summary information about tags
		my @tags = map { $_->tag } $entry->tags;
		$tags{$_}->{total_dollars} += $entry->amount foreach @tags;
		$tags{$_}->{count}++ foreach @tags;
		
		$count_total++;
		$dollar_total += $entry->amount;

		# output grant geo info
        foreach my $loc (Grantsfire::Geocoder->addr_fields) {
            my $field = "adr_$loc";
            $entry_ret->{$field} = $entry->grant_vcard->$field;
        }
        # copy lon/lat
        my $vcard_geo_info = $geo_info->{$entry->grant_vcard->id};
        if ($vcard_geo_info) {
            $entry_ret->{lon} = $vcard_geo_info->{lon};
            $entry_ret->{lat} = $vcard_geo_info->{lat};
        }
				
        delete $entry_ret->{$_} foreach qw/grantor grantee grant_vcard feed id/;  # remove these fields
		push @grants, $entry_ret;
	}
	
	# look up tags and build some reports
	my @tags_ret;
	while (my ($tag, $info) = each %tags) {
		my $dollar_percent = $dollar_total ?
			($info->{total_dollars} / $dollar_total * 100) : 0;
			
		my $count_percent = $count_total ?
			($info->{count} / $count_total * 100) : 0;	
				
		push @tags_ret, {
			name                  => $tag,
			count                 => $info->{count},
			total_dollars         => $info->{total_dollars},
			percent_total_dollars => sprintf("%.2f", $dollar_percent),
			percent_count         => sprintf("%.2f", $count_percent),
		};
	}
	
	my $res = {
		grant => \@grants,
		tag   => \@tags_ret,
	};
	
	return $res;
}

# return query split by whitespace
sub get_query_words : Private {
	my ($self, $c) = @_;

    my $q = $c->req->params->{q};
    return unless defined $q;

    $q =~ /(^\s+|\s+$)/g;
    my @words = split /\s+/, $q;
	return \@words;
}

sub get_query : Private {
	my ($self, $c) = @_;
		
	my $words = $c->forward('get_query_words') || [];

    $c->req->params->{by} ||= 'all';

	my @fields;
	my $query = {};
    for ($c->req->params->{by}) {
        /^grant$/ and do {
            @fields = qw/title description/;
            last;
        };
        /^grantor$/ and do {
            @fields = qw/grantor.org grantor.url/;
            last;
        };
        /^grantee$/ and do {
            @fields = qw/grantee.org grantee.url/;
            last;
        };
        # default
        @fields = qw/title description grantor.org grantee.org grantor.url grantee.url/;
        last;
    }

    for my $word (@$words) {
        my $or;
        push(@{$or->{'-or'}}, $_ => {like => "\%$word%"}) for @fields;
        push @{$query->{'-and'}}, $or;
    }

	return $query;
}

sub search : Local {
    my ($self, $c, %params) = @_;

    return $c->forward('/grant/asearch', [%params]) if $c->req->params->{a};
   
	my $query = $c->forward('get_query');
	
    my $page = delete $params{page} || $c->req->params->{page} || 1;
    my $rs = $c->model('GF::Entry')->search(
        $query,
        {
            order_by => 'modified DESC', 
            rows => 10, 
            join => [qw/grantor grantee/],
            %params
        }
        )->page($page);
    $c->stash->{grantpager} = $rs->pager;
    $c->stash->{grants} = [$rs->all];

	my $words = $c->forward('get_query_words') || [];
    my $search = $c->model('GF::Search')->find_or_create({query => join(' ', @$words)});
    $search->hits(($search->hits || 0) + 1);
    $search->update;
    $c->stash->{this_is_a_form} = 1;
}

sub asearch : Local {
    my ($self, $c, %params) = @_;

    my $query = undef;
    return unless defined $c->req->params->{s};
    my %simple_fields = (
        title                         => [],
        'grantee.org'                 => [],
        'grantee.adr_country_name'    => [],
        'grantee.adr_region'          => [],  
        'grantee.adr_locality'        => [],
        'grantor.org'                 => [],
        'grantor.adr_country_name'    => [],
        'grantor.adr_region'          => [],
        'grantor.adr_locality'        => [],
        keywords                      => [qw/title description grantor.org grantee.org/]
    );
    for my $field (keys %simple_fields) {
        my $q = $c->req->params->{$field};
        $q =~ s/(^\s+|\s+$)//g;
        my @words = split /\s+/, $q;
        for my $word (@words) {
            if (@{$simple_fields{$field}}) {
                my $or;
                push(@{$or->{'-or'}}, $_ => {like => "\%$word%"}) for @{$simple_fields{$field}};
                push @{$query->{'-and'}}, $or;
            }
            else {
                push(@{$query->{'-and'}}, $field => {like => "\%$word%"});
            }
        }
    }
    $c->req->params->{$_} =~ s/(^\s+|\s+$)// for qw/amount_minimum amount_maximum begins ends/;
    if ($c->req->params->{what_minimum} eq 'atleast' 
        and $c->req->params->{amount_minimum} =~ /\d/) {
        push(@{$query->{'-and'}}, amount => {'>=' => $c->req->params->{amount_minimum}});
    }
    if ($c->req->params->{what_maximum} eq 'atmost' 
        and $c->req->params->{amount_maximum} =~ /\d/) {
        push(@{$query->{'-and'}}, amount => {'<=' => $c->req->params->{amount_maximum}});
    }
    if ($c->req->params->{begins_when} ne 'any' 
        and $c->req->params->{begins} =~ /\d/) {
        push(@{$query->{'-and'}}, start_date => {
                ($c->req->params->{begins_when} eq 'before' ? '<=' : '>=')  => $c->req->params->{begins}
            });
    }
    if ($c->req->params->{ends_when} ne 'any' 
        and $c->req->params->{ends} =~ /\d/) {
        push(@{$query->{'-and'}}, end_date => {
                ($c->req->params->{ends_when} eq 'before' ? '<=' : '>=')  => $c->req->params->{ends}
            });
    }
    my $page = delete $params{page} || $c->req->params->{page} || 1;
    my $rs = $c->model('GF::Entry')->search(
        $query,
        {
            order_by => 'modified DESC', 
            rows => 10, 
            join => [qw/grantor grantee/],
            %params
        }
        )->page($page);
    $c->stash->{grantpager} = $rs->pager;
    $c->stash->{grants} = [$rs->all];
    $c->stash->{this_is_a_form} = 1;
}

1;
